#ifndef __M_LOG_H__
#define __M_LOG_H__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "util.hpp"
#include "formatter.hpp"
#include "level.hpp"
#include "sink.hpp"
#include "loop.hpp"
#include <mutex>
#include <atomic>
#include <cstdarg>
#include <unordered_map>

namespace Mylog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, LogLevel::value limit_level, Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks)
            : _logger_name(logger_name), _limit_level(limit_level), _formatter(formatter), _sinks(sinks.begin(), sinks.end())
        {
        }
        const std::string& name() { return _logger_name; }
        // 构造日志消息对象并格式化，得到格式化消息字符串后，进行落地输出
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (_limit_level > LogLevel::value::DEBUG)
                return;
            // 2. 通过fmt格式化字符串和不定参，得到对应的日志消息主体字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int n = vasprintf(&res, fmt.c_str(), ap);
            if (n < 0)
            {
                std::cout << "vasprintf failed!!!\n";
                return;
            }
            serialize(LogLevel::value::DEBUG, file, line, res);
            free(res); // 内存泄漏！！！
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (_limit_level > LogLevel::value::INFO)
                return;
            // 2. 通过fmt格式化字符串和不定参，得到对应的日志消息主体字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int n = vasprintf(&res, fmt.c_str(), ap);
            if (n < 0)
            {
                std::cout << "vasprintf failed!!!\n";
                return;
            }
            serialize(LogLevel::value::INFO, file, line, res);
            free(res); // 内存泄漏！！！
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (_limit_level > LogLevel::value::WARN)
                return;
            // 2. 通过fmt格式化字符串和不定参，得到对应的日志消息主体字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int n = vasprintf(&res, fmt.c_str(), ap);
            if (n < 0)
            {
                std::cout << "vasprintf failed!!!\n";
                return;
            }
            serialize(LogLevel::value::WARN, file, line, res);
            free(res); // 内存泄漏！！！
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (_limit_level > LogLevel::value::ERROR)
                return;
            // 2. 通过fmt格式化字符串和不定参，得到对应的日志消息主体字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int n = vasprintf(&res, fmt.c_str(), ap);
            if (n < 0)
            {
                std::cout << "vasprintf failed!!!\n";
                return;
            }
            serialize(LogLevel::value::ERROR, file, line, res);
            free(res); // 内存泄漏！！！
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断当前日志是否达到输出等级
            if (_limit_level > LogLevel::value::FATAL)
                return;
            // 2. 通过fmt格式化字符串和不定参，得到对应的日志消息主体字符串
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int n = vasprintf(&res, fmt.c_str(), ap);
            if (n < 0)
            {
                std::cout << "vasprintf failed!!!\n";
                return;
            }
            serialize(LogLevel::value::FATAL, file, line, res);
            free(res); // 内存泄漏！！！
        }

    protected:
        virtual void log(const char *data, size_t len) = 0;
        void serialize(LogLevel::value level, const std::string &file, size_t line, char *str)
        {
            // 3. 构造LogMsg对象
            LogMsg msg(level, file, line, _logger_name, str);
            // 4. 通过格式化工具对LogMsg进行格式化，得到格式化字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5. 进行日志落地
            log(ss.str().c_str(), ss.str().size());
        }

    protected:
        Formatter::ptr _formatter;
        std::atomic<LogLevel::value> _limit_level;
        std::vector<LogSink::ptr> _sinks;
        std::string _logger_name;
        std::mutex _mutex;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::value limit_level, Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks)
            : Logger(logger_name, limit_level, formatter, sinks)
        {
        }
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;
            for (auto sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name, LogLevel::value limit_level
            , Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks, LooperType async_type = LooperType::AsyncSafe)
            : Logger(logger_name, limit_level, formatter, sinks)
            , _async_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), async_type))
        {}
        void log(const char *data, size_t len) override{ _async_looper->push(data, len);}
        // 真实将日志进行落地函数，将缓冲区数据进行落地
        void realLog(Buffer &buffer)
        {
            if (_sinks.empty()) return;
            for (auto sink : _sinks)
            {
                sink->log(buffer.begin(), buffer.readAbleSize());
            }
        }
    private:   
        AsyncLooper::ptr _async_looper;
    };

    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    // 建造者模式来构造日志器
    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC), _limit_level(LogLevel::value::DEBUG), _looper_type(LooperType::AsyncSafe)
        {}
        void buildEnableUnsafeAsync() { _looper_type = LooperType::AsyncUnSafe; }
        void bulidLoggerType(LoggerType type) { _logger_type = type; }
        void bulidLoggerName(const std::string &name) { _logger_name = name; }
        void bulidLoggerLevel(LogLevel::value level) { _limit_level = level; }
        void bulidFormatter(const std::string &pattern) { _formatter = std::make_shared<Formatter>(pattern); }
        template <class SinkType, class... Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr build() = 0;

    protected:
        LooperType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::value _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };



    // 派生局部日志器建造者和全局日志器建造者（添加到全局单例管理）
    class localLoggerBuilder : public LoggerBuilder // 局部日志器建造者
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<Mylog::StdoutSink>();
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<Mylog::AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<Mylog::SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };


    class LoggerManager
    {
    public:
        static LoggerManager& GetInstance()
        {
            static LoggerManager eton;
            return eton;
        }
        void addLogger(Logger::ptr& logger)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end()) return false;
            return true;   
        }
        Logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end()) 
                return Logger::ptr();
            return it->second;
        }
        Logger::ptr rootLogger() { return _root_logger; }
    private:
        LoggerManager()
        {
            // 构造的时候，不能使用GlobalLoggerBuilder
            std::unique_ptr<Mylog::LoggerBuilder> bulider(new Mylog::localLoggerBuilder());
            bulider->bulidLoggerName("root");
            _root_logger = bulider->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }
        // LoggerManager(LoggerManager &) = delete;
        // LoggerManager& operator=(const LoggerManager& ) = delete;
    private:
        std::mutex _mutex;
        Logger::ptr _root_logger; // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };



    // 全局日志器建造者 —— 在局部日志器建造者就基础上，将新增日志器添加到单例对象中
    class GlobalLoggerBuilder : public LoggerBuilder 
    {
    public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<Mylog::StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == Mylog::LoggerType::LOGGER_ASYNC)
            {
                logger =  std::make_shared<Mylog::AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks, _looper_type);
            }
            else
            {
                logger = std::make_shared<Mylog::SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            LoggerManager::GetInstance().addLogger(logger);
            return logger;
        }
    };
}

#endif